/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package arithserverrpc;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 *
 * @author MCAS
 * Classe que representa a aplicação servidor da aplicação distribuída cliente-servidor
 */
public class ServerRPC {
    /**
     * Socket de comunicação
     */
    private static DatagramSocket socket;
    /**
     * Porta de comunicação do servidor
     */
    private static int porta;
    /**
     * Endereço de comunicação do servidor
     */
    private static InetAddress endereco;
    /**
     * Referencia a tela de configuração do servidor
     */
    private static ConfServerView conf;
    /**
     * Variavel de sinalização para erros aritmeticos (divisão por zero e estouro)
     */
    private static String ARITHEXCEPTION = "NULL";

    /**
     * Mensagem de erro para erros aritmeticos
     */
    private static String ERROR_MESSAGE = "Divisão por zero ou número de " +
            "casas decimais maiores que o suportado (10 casas)";

    /**
     * Inicia a aplicação servidor
     */
    public static void startUp() {
        try {
            conf.dispose();
            
            socket = new DatagramSocket(getPorta());

            byte[] buf = new byte[1024];

            System.out.println("Endereço do servidor: "+endereco.getHostAddress());
            System.out.println("Servidor iniciado e escutando em "+getPorta());
            
            while (true) {
                DatagramPacket request = new DatagramPacket(buf, buf.length);               

                socket.receive(request);

                System.out.println("Pedido requisitado por:" + request.getAddress());
                System.out.println("Pedido:"+ new String(request.getData()).
                        substring(request.getOffset(),request.getLength()));

                String result = null;
                try{
                    result = selectNRun(new Operator(new String(request.getData()).
                        substring(request.getOffset(),request.getLength())));
                }catch(ArithmeticException e){
                    System.out.println(getERROR_MESSAGE());
                    result = getARITHEXCEPTION();
                }
                
                System.out.println("Resultado:" + result);

                DatagramPacket reply = new DatagramPacket(result.getBytes(),result.getBytes().length,
                        request.getAddress(),request.getPort());
                
                socket.send(reply);
            }
        } catch (SocketException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

    /**
     * Este método trata a mensagem da requisição de um cliente;
     * Seleciona, a partir dos operadores na expressão, quais operações serão feitas;
     * Só funciona para dois termos.
     */
    public static String selectNRun(Operator op) throws ArithmeticException{
        
        String tempExpression = null;
        if (op.getExpression().startsWith("+") || op.getExpression().startsWith("-")) {
            tempExpression = op.getExpression().substring(1, op.getExpression().length());
            if (tempExpression.contains("*")) {
                return op.mult(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            } else if (tempExpression.contains("/")) {
                return op.div(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            } else if (tempExpression.contains("+")) {
                return op.add(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            } else if (tempExpression.contains("-")) {
                return op.sub(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            }
        }else{
            if (op.getExpression().contains("*")) {
                return op.mult(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            } else if (op.getExpression().contains("/")) {
                return op.div(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            } else if (op.getExpression().contains("+")) {
                return op.add(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            } else if (op.getExpression().contains("-")) {
                return op.sub(new BigDecimal(op.getOpA()), new BigDecimal(op.getOpB())).toEngineeringString();
            }
        }


        return "Esta operação não é válida";
    }

    /**
     * @return the porta
     */
    public static int getPorta() {
        return porta;
    }

    /**
     * @param aPorta the porta to set
     */
    public static void setPorta(int aPorta) {
        porta = aPorta;
    }

    /**
     * @return the conf
     */
    public static ConfServerView getConf() {
        return conf;
    }

    /**
     * @param conf the conf to set
     */
    public static void setConf(ConfServerView conf) {
        ServerRPC.conf = conf;
    }

    /**
     * @return the endereco
     */
    public static InetAddress getEndereco() {
        return endereco;
    }

    /**
     * @param aEndereco the endereco to set
     */
    public static void setEndereco(InetAddress aEndereco) {
        endereco = aEndereco;
    }

    /**
     * @return the ARITHEXCEPTION
     */
    public static String getARITHEXCEPTION() {
        return ARITHEXCEPTION;
    }

    /**
     * @param aARITHEXCEPTION the ARITHEXCEPTION to set
     */
    public static void setARITHEXCEPTION(String aARITHEXCEPTION) {
        ARITHEXCEPTION = aARITHEXCEPTION;
    }

    /**
     * @return the ERROR_MESSAGE
     */
    public static String getERROR_MESSAGE() {
        return ERROR_MESSAGE;
    }

    /**
     * @param aERROR_MESSAGE the ERROR_MESSAGE to set
     */
    public static void setERROR_MESSAGE(String aERROR_MESSAGE) {
        ERROR_MESSAGE = aERROR_MESSAGE;
    }

}
